#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__author__ = 'Justin'
__mtime__ = '2019-02-26'

"""

import os, csv, re
from src.util import get_project_root
from pypinyin import lazy_pinyin, pinyin, Style
from tqdm import tqdm
from vocabulary import Vocabulary

PROJECT_ROOT = get_project_root()


def sort_pinyin(hanzi_list):
    hanzi_list_pinyin = []
    hanzi_list_pinyin_alias_dict = {}
    for single_str in hanzi_list:
        # py_r = lazy_pinyin(single_str)
        py_r = pinyin(single_str, style=Style.TONE2)
        single_str_py = ''
        for py_list in py_r:
            single_str_py = single_str_py + py_list[0]
        hanzi_list_pinyin.append(single_str_py)
        hanzi_list_pinyin_alias_dict[single_str_py] = single_str
    hanzi_list_pinyin.sort()
    sorted_hanzi_list = []
    for single_str_py in hanzi_list_pinyin:
        sorted_hanzi_list.append(hanzi_list_pinyin_alias_dict[single_str_py])
    return sorted_hanzi_list


class Record_Reader(object):

    def __init__(self):

        self.voc = Vocabulary()
        # self.entity_type, self.SET_ENTITIES = None, None

    def output_filtered_records(self, filename, key_word, start, end):
        '''
        将诊断数据CSV文件中的需要部分读出，并存盘
        :param filename: 诊断数据CSV文件
        :param key_word:  诊断数据必须包括的关键词
        :param start: 输入诊断数据的开始编号，小于此编号的忽略
        :param end: 输入数据的终止编号，大于此编号，则退出
        :return:
        '''
        csv_file = csv.reader(open(PROJECT_ROOT + '//data//' + filename, 'r', encoding='utf-8'))
        # 性别,年龄,住院号,科室,登记日期,诊断结果
        count = 1
        result = []
        for item in csv_file:
            department = item[3].strip()
            if key_word in department:
                if end >= count >= start:
                    sex = item[0]
                    if len(item[1]) > 0 and '岁' in item[1]:
                        age = int(item[1].replace('岁', '').strip())
                    else:
                        age = -1

                    if len(item[2]) > 0:
                        hospital_id = int(item[2])
                    else:
                        hospital_id = -1
                    # department = key_word
                    date = item[4]

                    text = item[5].replace('（', '(').replace('）', ')').replace(" ", "")
                    if len(text) > 0:
                        # 预处理，将一些简写进行扩充，以简化后续的处理
                        text = self.extended_shorthand(key_word, text)

                        # 将句首的一对括号，替换为句号。
                        if text.startswith("("):
                            # 寻找右括号
                            pos = text.find(')')
                            if pos > 4:
                                text = text[1:pos] + "。" + text[pos + 1:]
                            elif pos > 0:
                                text = text[1:pos] + text[pos + 1:]
                        # 所有的分数两边没有括号的加上括号。待补充。

                        # 将换行符替换为$，将括号统一为英文的，去掉中间的所有空格。将一个样本调整到csv文件中的一行。
                        text = text.replace("\n", "$")
                        # assert len(text)> 0,  "{}, the length of text is zero. ".format(item)

                        result.append((sex, age, hospital_id, key_word, date, text))
                        count += 1
                elif count > end + 1:
                    break

        original_txt = "{}//data//{}-{}-{}_病理诊断数据.csv".format(PROJECT_ROOT,
                                                              key_word, start,
                                                              start + len(result) - 1)

        f = open(original_txt, "w", encoding='utf-8')
        for sex, age, hospital_id, department, date, text in result:
            row = "{},{},{},{},{},\"{}\"\n".format(sex, age, hospital_id, department, date, text)
            f.write(row)
        f.close()

    def extended_shorthand(self, key_word, text):
        if key_word == "乳腺":
            items = [("(右)", "(右乳)"), ("(左)", "(左乳)"), ("(左、右)", "(双乳)"),
                     ("(双)", "(双乳)"), ("(双侧)", "(双乳)")]
            for original, alternative in items:
                text = text.replace(original, alternative)
        return text

    def labeling_with_template_matching(self, filename, key_word, start, end, extend=False):
        '''
        从诊断CSV文件中，读入数据，按词典中的词进行匹配，生成人工标注文件，并存盘
        :param filename: 诊断数据文件
        :param key_word: 诊断数据必须包括的关键词
        :param start: 输入诊断数据的开始编号，小于此编号的忽略
        :param end: 输入数据的终止编号，大于此编号，则退出
        :param extend: 是否使用规则推理出非NER使用的Tags，为训练DP而生成的
        :return:
        '''
        self.voc.load_vocabulary()

        csv_file = csv.reader(open(PROJECT_ROOT + '//data//' + filename, 'r', encoding='utf-8'))
        # 性别,年龄,住院号,科室,登记日期,诊断结果
        count = 1
        result = []
        for item in csv_file:
            assert len(item) == 6, "Error: COL num is not 6."
            department = item[3].strip()
            if key_word in department:
                if end >= count >= start:
                    text = item[5]
                    # for i in range(6, len(item)):  # 防止出现多的逗号分割
                    #     text += item[i]
                    result.append(text.replace("\n", "$").upper())
                elif count > end + 1:
                    break
                count += 1

        for k, original in enumerate(result):
            print("original txt: ", original)
            if extend:
                results = self.template_matching_extra_tags(original)
                self.save(k + start, original, results, "dp_txt")
            else:
                results = self.template_matching_tags(original)
                self.save(k + start, original, results, "ner_txt")

        return

    def template_matching_tags(self, original):
        results = []
        for entity_name, entity_set in self.voc.SET_ENTITIES:
            temp_result = self.vocabulary_matching_tags(entity_set, entity_name, original)
            results.extend(temp_result)

        results = self.remove_duplicates(results)
        results = self.merge_SIGNS_tags(results)
        return results

    def template_matching_extra_tags(self, original):
        results = []
        for entity_name, entity_set in self.voc.SET_ENTITIES:
            # if entity_name == "症状和体征":
            #     entity_set.difference_update(self.voc.SET_SIGNS_AFF)

            temp_result = self.vocabulary_matching_tags(entity_set, entity_name, original)
            results.extend(temp_result)

        for entity_name, entity_set in self.voc.EXTRA_ENTITIES:
            if entity_name != "症状和体征A":
                temp_result = self.vocabulary_matching_tags(entity_set, entity_name, original)
                results.extend(temp_result)

        match_result = self.regular_matching_RESULT_tag(original)
        results.extend(match_result)

        results = self.remove_duplicates(results)
        results = self.merge_SIGNS_tags(results)
        return results

    def vocabulary_matching_tags(self, entity_set, entity_name, input_text):
        '''
        根据设定的字典，生成人工标注文件，以便进一步人工精确校正
        :param entity_set: 由某种标签所对应的字典
        :param entity_name: 某种标签，包括治疗，身体部位等
        :param input_text: 输入文本
        :return:
        '''
        result = []
        for key_word in entity_set:
            pos = 0
            bias = len(key_word) - 1
            while pos >= 0:
                pos = input_text.find(key_word, pos)
                if pos != -1:
                    # print("{}\t{}\t{}\t{}".format(key_word, pos, pos + bias, entity_name))
                    result.append((key_word, pos, pos + bias, entity_name))
                    pos += 1

        return result

    def regular_matching_RESULT_tag(self, input_text):
        '''
        用正则表达式，匹配出（）内的检查结果。
        :param input_text: 输入文本
        '''
        text = input_text.replace('（', '(').replace('）', ')')
        # print(text)
        pattern = re.compile("[(][^(#)]*[)]")
        match = pattern.finditer(text)

        result = []
        SET_ENTITIES = []
        SET_ENTITIES.extend(self.voc.SET_ENTITIES)
        SET_ENTITIES.extend(self.voc.EXTRA_ENTITIES)
        # entity_name = "结果"
        for item in match:
            # print(item.group().upper(), item.start(), item.end(), )
            key_word = item.group().upper()

            tag = True
            for _, entity_set in SET_ENTITIES:
                for vocabulary in entity_set:
                    if vocabulary in key_word:
                        tag = False
                        break
                if not tag:
                    break
            if tag:
                result.append((key_word, item.start(), item.end() - 1, "结果"))
        return result

    def merge_SIGNS_tags(self, terms):
        '''
        将连续的SIGN标志组合起来
        :param terms: 标注的集合
        :return:
        '''
        # 对列表的第二个元素排序后，再对第3个元素排序
        terms.sort(key=lambda x: (x[1], x[2]))
        results = []
        count = len(terms)
        iter_items = iter(range(count))
        for index in iter_items:
            item = terms[index]
            word, begin, end, tag = item

            if index + 1 >= count:
                results.append(item)
            else:
                for next_index in range(index + 1, count):
                    next_item = terms[next_index]
                    next_word, next_begin, next_end, next_tag = next_item

                    if tag == "症状和体征" and (tag == next_tag) and next_begin - end <= 1:
                        # 合并两项
                        item = (word + next_word, begin, next_end, tag)
                        word, begin, end, tag = item
                        iter_items.__next__()

                        if next_index + 1 >= count:
                            results.append(item)

                    else:
                        results.append(item)
                        break

        return results

    def remove_duplicates(self, terms):
        '''
        去除自动 生成的 人工标注文件中的明显冗余
        :param terms:人工标注的集合
        :return:
        '''
        # 对列表的第二个元素排序后，再对第3个元素排序
        terms.sort(key=lambda x: (x[1], x[2]))
        results = []
        count = len(terms)
        for index in range(count):
            item = terms[index]
            begin = item[1]
            end = item[2]
            tag = True
            for k in range(count):
                if k == index:
                    continue

                item2 = terms[k]
                begin2 = item2[1]
                end2 = item2[2]
                # 是否被包含
                #   begin, end
                #   begin2,    end2
                if begin2 <= begin and end2 >= end:
                    tag = False
                    break

            # 只保留最长的 实体名
            if tag:
                results.append(item)

        return results

    def save(self, id, original, terms, path):
        '''
        存盘
        :param id: 数据在诊断CSV中的编号（序号）
        :param original: 输入文本
        :param terms: 生成的标注信息
        :parm path: 存盘文件夹
        :return:
        '''
        save_path = "{}//data//{}".format(PROJECT_ROOT, path)
        if not os.path.exists(save_path):
            os.makedirs(save_path)

        original_txt = "{}//病理诊断-{}.txtoriginal.txt".format(save_path, id)
        txt = "{}//病理诊断-{}.txt".format(save_path, id)

        f = open(original_txt, "w", encoding='utf-8')
        f.write(original)
        f.close()

        f = open(txt, "w", encoding='utf-8')
        count = 0
        len_terms = len(terms)
        for item in terms:
            print(item)
            f.write("{}\t{}\t{}\t{}".format(item[0], item[1], item[2], item[3]))
            count += 1
            if count < len_terms:
                f.write("\n")

        f.close()

# # 发生重叠
# #     begin, end
# #          begin2, end2
# elif begin2 < end:
#
# break

# def labeling_with_template_matching(self, filename, key_word, start, end):
#     '''
#     从诊断CSV文件中，读入数据，按词典中的词进行匹配，生成人工标注文件，并存盘
#     :param filename: 诊断数据文件
#     :param key_word: 诊断数据必须包括的关键词
#     :param start: 输入诊断数据的开始编号，小于此编号的忽略
#     :param end: 输入数据的终止编号，大于此编号，则退出
#     :return:
#     '''
#     # 准备数据
#     self.entity_type, self.SET_ENTITIES = self.voc.load_vocabulary()
#
#     csv_file = csv.reader(open(PROJECT_ROOT + '//data//' + filename, 'r', encoding='utf-8'))
#     # 性别,年龄,住院号,科室,登记日期,诊断结果
#     count = 1
#     result = []
#     for item in csv_file:
#         assert len(item) == 6, "Error: COL num is not 6."
#         department = item[3].strip()
#         if key_word in department:
#             if end >= count >= start:
#                 text = item[5]
#                 # for i in range(6, len(item)):  # 防止出现多的逗号分割
#                 #     text += item[i]
#                 result.append(text.replace("\n", "$").upper())
#             elif count > end + 1:
#                 break
#             count += 1
#
#     for k, original in enumerate(result):
#         print("original txt: ", original)
#         results = self.template_matching_tags(original)
#         self.save(k + start, original, results)

# def template_matching_tags(self, original):
#     results = []
#     for entity_name, entity_set in self.SET_ENTITIES:
#         temp_result = self.vocabulary_matching_tags(entity_set, entity_name, original)
#         results.extend(temp_result)
#
#     match_result = self.regular_matching_RESULT_tag(original)
#     results.extend(match_result)
#     results = self.remove_duplicates(results)
#     results = self.merge_SIGNS_tags(results)
#     return results
